package com.onefish.toolkit;

import com.onefish.toolkit.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;

@Component
public class DesignPatterns {
    //函数式编程,减少if/else以及switch/case的数量
    private static final Map<String, Function<String, String>> functionsMap = new HashMap<>();
    @Autowired
    private TestService testService;

    //初始化完bean以及依赖注入后调用该方法
    @PostConstruct
    public void initor() {
        functionsMap.put(CommonEnum.A.getType(), type -> testService.readA(type));
        functionsMap.put(CommonEnum.B.getType(), type -> testService.readB(type));
        functionsMap.put(CommonEnum.C.getType(), type -> testService.readC(type));
        functionsMap.put(CommonEnum.D.getType(), type -> testService.readD(type));
    }

    public String getResult(String type) {
        Function<String, String> function = functionsMap.get(type);
        return function == null ? "不存在该类型" : function.apply(type);
    }

    /**
     * 单例模式
     */
    public static class Singleton {
        private static Singleton instance;

        //        private static Singleton instance = new Singleton();  //  饿汉模式
        private static final ThreadLocal<Singleton> singletonThreadLocal =
                ThreadLocal.withInitial(Singleton::new);
        private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<>();

        private static class SingletonHolder {
            private static Singleton instance = new Singleton();
        }

        public Singleton() {
        }

        //  懒汉模式-2种（加synchronized是线程安全，不加线程不安全）
        public synchronized static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }

        //  双重校验锁法（通常线程安全，低概率不安全）
        //  volatile法（instance加上volatile保证了内存屏障）
        public static Singleton getInstance2() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }

        //  静态内部类加载
        public static Singleton getInstance3() {
            return SingletonHolder.instance;
        }

        //  ThreadLocal法（线程安全，以空间换取时间）
        public static Singleton getInstance4() {
            return singletonThreadLocal.get();
        }

        //   CAS法保证线程安全
        public static final Singleton getInstance5() {
            for (; ; ) {
                Singleton current = INSTANCE.get();
                if (current != null) {
                    return current;
                }
                current = new Singleton();
                if (INSTANCE.compareAndSet(null, current)) {
                    return current;
                }
            }
        }

        //  枚举法 -推荐
        public enum SingletonEnum {
            INSTANCE;
        }

        public void test() {
            System.out.println("我是单例模式");
        }
    }

    /**
     * 观察者模式 <发布与订阅>
     */
    public interface Publisher {
        public void publishMessage(String message);
    }

    public static class PL extends Observable implements Publisher {
        @Override
        public void publishMessage(String message) {
            System.out.println("此条通知将发送给" + this.countObservers() + "个订阅者！");
            System.out.println("通知内容如下: " + message);
            this.setChanged();
            this.notifyObservers(message);
        }
    }

    public static class Subscriber implements Observer {
        private String name;

        public Subscriber(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public void update(Observable o, Object arg) {
            System.out.println("用户：" + this.name + "，接受到的信息：" + arg);
        }
    }

    /**
     * 代理模式（静态+动态）
     */
    public interface ISubject {
        public String test();
    }

    public static class RealSubject implements ISubject {

        @Override
        public String test() {
            System.out.println("此方法是目标对象的");
            return "我是目标对象";
        }
    }

    //  静态代理
    public static class Proxy implements ISubject {
        private RealSubject targetSubject;

        public Proxy(RealSubject subject) {
            this.targetSubject = subject;

        }

        @Override
        public String test() {
            System.out.println("此方法是代理对象的");
            String target = targetSubject.test();
            return target + " && 我是代理对象";
        }
    }

    //  动态代理 -jdk方式
    public static class DynamicProxy implements InvocationHandler {
        private Object target;

        public DynamicProxy(Object o) {
            this.target = o;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("在调用方法之前做一些事情");
            Object result = method.invoke(this.target, args);
            System.out.println("在调用方法之后做一些事情");
            return result + " && 我是代理对象";
        }
    }

    //  动态代理 -cglib方式
    public static class BusinessObject {
        public void customMethod() {
            System.out.println("执行了BusinessObject业务方法-customMethod");
        }
    }

    //  cglib方法拦截器
    public static class CustomMethodInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("在调用方法之前做一些事情");
            // 调用目标对象的方法
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("在调用方法之后做一些事情");
            return result;
        }
    }

    /**
     * 工厂模式
     */
    // 接口：数据库驱动程序
    public static interface DatabaseDriver {
        void connect();
    }

    // 实现类：MySQL数据库驱动程序
    public static class MySQLDriver implements DatabaseDriver {
        @Override
        public void connect() {
            System.out.println("Connecting to MySQL database...");
        }
    }

    // 实现类：Oracle数据库驱动程序
    public static class OracleDriver implements DatabaseDriver {
        @Override
        public void connect() {
            System.out.println("Connecting to Oracle database...");
        }
    }

    // 工厂类：数据库驱动程序工厂
    public static class DatabaseDriverFactory {
        public static DatabaseDriver createDriver(String driverType) {
            if ("MySQL".equalsIgnoreCase(driverType)) {
                return new MySQLDriver();
            } else if ("Oracle".equalsIgnoreCase(driverType)) {
                return new OracleDriver();
            }
            return null;
        }
    }

    /**
     * 享元模式
     */
    static class ShapeFactory {
        private static final HashMap<String, Shape> shapes = new HashMap<>();

        public static Shape getShape(String color) {
            Shape shape = shapes.get(color);

            if (shape == null) {
                shape = new Circle(color);
                shapes.put(color, shape);
            }

            return shape;
        }
    }

    /**
     * 抽象享元类
     */
    interface Shape {
        void draw();
    }

    // 具体享元类
    static class Circle implements Shape {
        private String color;

        public Circle(String color) {
            this.color = color;
        }

        @Override
        public void draw() {
            System.out.println("Drawing a " + color + " circle");
        }
    }

    /**
     * 适配器模式
     */
    public interface HandlerAdapter {
        boolean supports(Object handler);

        void handle(Object handler);
    }

    // 具体的适配器实现类
    public static class SimpleHandlerAdapter implements HandlerAdapter {
        @Override
        public boolean supports(Object handler) {
            return (handler instanceof SimpleController);
        }

        @Override
        public void handle(Object handler) {
            ((SimpleController) handler).handleRequest();
        }
    }

    // 控制器接口
    public interface Controller {
        void handleRequest();
    }

    // 具体的控制器实现类
    public static class SimpleController implements Controller {
        @Override
        public void handleRequest() {
            System.out.println("Handling request in SimpleController");
        }
    }

    // 前端控制器
    public static class DispatcherServlet {
        private List<HandlerAdapter> handlerAdapters;

        public DispatcherServlet() {
            handlerAdapters = new ArrayList<>();
            handlerAdapters.add(new SimpleHandlerAdapter());
        }

        public void doDispatch(Object handler) {
            HandlerAdapter adapter = getHandlerAdapter(handler);
            adapter.handle(handler);
        }

        private HandlerAdapter getHandlerAdapter(Object handler) {
            for (HandlerAdapter adapter : handlerAdapters) {
                if (adapter.supports(handler)) {
                    return adapter;
                }
            }
            return null;
        }
    }

    public static void main(String[] args) throws Throwable, Exception {
        //  单例模式单测 -9种
        Singleton.getInstance().test();
        //  观察者模式单测
        Subscriber subscriber = new Subscriber("A");
        Subscriber subscriber2 = new Subscriber("B");
        PL pl = new PL();
        pl.addObserver(subscriber);
        pl.addObserver(subscriber2);
        pl.publishMessage("hello world！");
        //  代理模式单测
        //  静态代理模式
        RealSubject subject = new RealSubject();
        Proxy proxy = new Proxy(subject);
        String proxyStr = proxy.test();
        System.out.println(proxyStr);
        //  动态代理模式 -jdk
        RealSubject targetObj = new RealSubject();
        DynamicProxy dynamicProxy = new DynamicProxy(targetObj);
        Method method = targetObj.getClass().getMethod("test");     //  根据反射获取目标对象的方法
        Object dynamicProxyStr = dynamicProxy.invoke(targetObj, method, args);
        System.out.println(dynamicProxyStr);
        //  动态代理模式 -cglib
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\temp");   // 设置代理类生成的路径，方便查看生成的代理类
        Enhancer enhancer = new Enhancer();     // 创建Enhancer对象，用于生成代理类
        enhancer.setSuperclass(BusinessObject.class);   // 设置代理类的父类
        enhancer.setCallback(new CustomMethodInterceptor());     // 设置回调对象，即MethodInterceptor
        BusinessObject proxyObject = (BusinessObject) enhancer.create();      // 创建代理对象
        proxyObject.customMethod();     // 通过代理对象调用方法
        //  工厂模式单测
        DatabaseDriver databaseDriver = DatabaseDriverFactory.createDriver("mysql");
        databaseDriver.connect();
        //  享元模式单侧
        Shape redCircle = ShapeFactory.getShape("red");
        redCircle.draw();
        Shape blueCircle = ShapeFactory.getShape("blue");
        blueCircle.draw();
        Shape redCircle2 = ShapeFactory.getShape("green");
        redCircle2.draw();
        //  适配器模式单测
        DispatcherServlet dispatcherServlet = new DispatcherServlet();
        Controller controller = new SimpleController();
        dispatcherServlet.doDispatch(controller);
    }
}
